26장 ES6 함수의 추가 기능
함수의 구분
es6 이전에는 함수의 구분이없었는데, 이제 구분해서 사용한다.
메서드
es6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미한다.
es6 메서드는 인스턴스 생성할 수 없는 non-constructor 이다.
표준 빌드인 객체가 제공하는 프로토타입 메서드와 정적 메서드는 모두 non-constructor 임.
25장 클래스에서 봤던 것처럼 내부 슬롯을 가지고 super을 참조할 수 있다.
화살표 함수
화살표 함수와 일반함수 차이
- 화살표 함수는 인스턴스를 생성할 수 없는 non-constructor
- 중복된 매개변수 이름을 선언할 수 없다.
- 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다.
스코프 체인을 통해 상위 스코프의 값들을 참조한다.
this
22장 this 참고
class Prefixer {
constructor(prefix) {
this.prefix = prefix;
}
add(arr) {
// add 메서드는 인수로 전달된 배열 arr을 순회하며 배열의 모든 요소에 prefix를 추가한다.
// ①
return arr.map(function (item) {
return this.prefix + item; // ②
// -> TypeError: Cannot read property 'prefix' of undefined
});
}
}
const prefixer = new Prefixer('-webkit-');
console.log(prefixer.add(['transition', 'user-select']));
map에 전달된 callback 함수는 일반함수로 호출된다. 일반 함수의 호출 시 this는 전역 객체를 가르키지만, class 안에서는 strict mode가 적용되어서 this에 undefined가 바인딩되어 에러가 발생하는 모습.
콜백 함수 내부의 this문제를 해결하기 위한 방법들
- that 사용
- 고차함수에 this전달
- bind 메서드 이용해서 this 바인딩
add(arr) {
// this를 일단 회피시킨다.
const that = this;
return arr.map(function (item) {
// this 대신 that을 참조한다.
return that.prefix + ' ' + item;
});
}
add(arr) {
return arr.map(function (item) {
return this.prefix + ' ' + item;
}, this); // this에 바인딩된 값이 콜백 함수 내부의 this에 바인딩된다.
}
add(arr) {
return arr.map(function (item) {
return this.prefix + ' ' + item;
}.bind(this)); // this에 바인딩된 값이 콜백 함수 내부의 this에 바인딩된다.
}
화살표 함수를 사용한 this 문제 해결
class Prefixer {
constructor(prefix) {
this.prefix = prefix;
}
add(arr) {
return arr.map(item => this.prefix + item);
}
}
const prefixer = new Prefixer('-webkit-');
console.log(prefixer.add(['transition', 'user-select']));
// ['-webkit-transition', '-webkit-user-select']
화살표 함수 내부에서 this를 참조하면 상위 스코프의 this를 그대로 참조한다.
이를 lexical this 라고 한다.
화살표 함수 자체는 this바인딩을 갖기 때문에 bind 메서드를 사용해서 화살표 내부의 this를 교체할 수 없다.
메서드를 화살표 함수로 정의할 때 주의해야한다. this가 메서드를 호출한 객체를 가르키지 않기 떄문에. 프로토타입 객체에서도 프로퍼티에 화살표 함수 할당하면 동일한 문제 생길 수 잇음
// Bad
function Person(name) {
this.name = name;
}
Person.prototype.sayHi = () => console.log(`Hi ${this.name}`);
const person = new Person('Lee');
// 이 예제를 브라우저에서 실행하면 this.name은 빈 문자열을 갖는 window.name과 같다.
person.sayHi(); // Hi
클래스 필드에 화살표 함수 할당할 수도 있다.
그럴 경우 프로토타입 메서드가 아니라, 인스턴스의 메서드가 된다. (클래스필드에서 선언하니까)
// Bad
class Person {
// 클래스 필드 정의 제안
name = 'Lee';
sayHi = () => console.log(`Hi ${this.name}`);
}
const person = new Person();
person.sayHi(); // Hi Lee
super
화살표 함수에서 super을 참조하면 상위 스코프의 super을 참조한다.
class Base {
constructor(name) {
this.name = name;
}
sayHi() {
return `Hi! ${this.name}`;
}
}
class Derived extends Base {
// 화살표 함수의 super는 상위 스코프인 constructor의 super를 가리킨다.
sayHi = () => `${super.sayHi()} how are you doing?`;
}
const derived = new Derived('Lee');
console.log(derived.sayHi()); // Hi! Lee how are you doing?
Rest 파라미터
매개변수 이름 앞에 … 붙여서 정의한 매개변수를 의미함
Rest 파라미터는 함수에 전달된 인수들의 목록을 배열로 전달 받는다
function foo(...rest) {
// 매개변수 rest는 인수들의 목록을 배열로 전달받는 Rest 파라미터다.
console.log(rest); // [ 1, 2, 3, 4, 5 ]
}
foo(1, 2, 3, 4, 5);
- 반드시 마지막에 와야한다.
- 하나만 선언할 수 있다.
- 함수 객체의 length 프로퍼티에 영향 주지 않음.
- arguments 는 유사배열인데 반해 Rest는 배열임
- 화살표 함수는 arguments 없으니까 Rest 쓰셈.
매개변수 기본값
매개변수 기본값 설정할 수 있음.
function logName(name = 'Lee') {
console.log(name);
}
logName(); // Lee
logName(undefined); // Lee
logName(null); // null